/*******************************************************************************
 * Copyright (c) 2014 Francesco Gabbrielli
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Francesco Gabbrielli - initial API and implementation
 ******************************************************************************/
package it.francescogabbrielli.android.solidalapp.home;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.SherlockDialogFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.model.LatLng;

import it.francescogabbrielli.android.solidalapp.Action;
import it.francescogabbrielli.android.solidalapp.Constants;
import it.francescogabbrielli.android.solidalapp.DataEvent;
import it.francescogabbrielli.android.solidalapp.EndpointsLoader;
import it.francescogabbrielli.android.solidalapp.EndpointsUtils;
import it.francescogabbrielli.android.solidalapp.GCMMessageReceiver;
import it.francescogabbrielli.android.solidalapp.MessageActivity;
import it.francescogabbrielli.android.solidalapp.NetworkUtils;
import it.francescogabbrielli.android.solidalapp.R;
import it.francescogabbrielli.android.solidalapp.SolidalApp;
import it.francescogabbrielli.android.solidalapp.SolidalApp.DataKey;
import it.francescogabbrielli.android.solidalapp.actions.EndpointsInsertRequest;
import it.francescogabbrielli.android.solidalapp.actions.EndpointsRemoveRequest;
import it.francescogabbrielli.android.solidalapp.deviceendpoint.model.Device;
import it.francescogabbrielli.android.solidalapp.file.RequestFileActivity;
import it.francescogabbrielli.android.solidalapp.profile.RequestProfileActivity;
import it.francescogabbrielli.android.solidalapp.profileendpoint.model.Profile;
import it.francescogabbrielli.android.solidalapp.requestendpoint.model.Request;
import it.francescogabbrielli.android.solidalapp.response.ResponseActivity;
import it.francescogabbrielli.android.solidalapp.responseendpoint.model.Response;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.Loader;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.EditText;
import android.widget.Toast;

public class HomeActivity extends MessageActivity<Request> 
	implements HomeFragmentListener {
	
	class CheckExpiry extends TimerTask {		
		@Override
		public void run() {
			
			final Request req = (Request) app.getData(DataKey.REQUEST);
			if (req==null) {
				descheduleCheckExpiry();
				return;
			}
			
			boolean isAccepted = req.getAccepted()!=null && req.getAccepted();
			if (req.getId()!=null && req.getExpiry()<System.currentTimeMillis() && !isAccepted) {
				new Handler(getApplicationContext().getMainLooper()).post(new Runnable() {
					@Override
					public void run() {
						// reset request
						if (req==app.getData(DataKey.REQUEST)) {
							req.setExpired(true);
							app.alert(R.string.request_expired);
							app.fireDataChanged(new DataEvent(this, DataKey.REQUEST, true));
						}
					}
				});
				descheduleCheckExpiry();
			}
		}
	}
	
	private Timer checkExpiry;
	
	private void scheduleCheckExpiry() {
		if (checkExpiry==null) {
			checkExpiry = new Timer();
			checkExpiry.scheduleAtFixedRate(new CheckExpiry(), 600, 60000);
		}
	}
	
	private void descheduleCheckExpiry() {
		if (checkExpiry!=null) {
			checkExpiry.cancel();
			checkExpiry = null;
		}
	}
	
	/** Current sending request, ready for dispatch */
	private Request request;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.baseactivity_home);

		if (app.getStatus().getGcmId()==null)
			checkPlayServices();
		
		ActionBar actionBar = getSupportActionBar();
		
	    // two fragments layout
	    if (!getResources().getBoolean(R.bool.notabs)) {
	    	actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
	    	addTab(R.string.home_tab_request, R.id.home_tab_container, "request", RequestDataFragment.class);
	    	addTab(R.string.home_tab_map, R.id.home_tab_container, "map", RequestMapFragment.class);
	    } else {
	    	RequestFragment homeFragment = (RequestFragment) getSupportFragmentManager().findFragmentByTag("request");
	    	if(homeFragment==null) {
	    		homeFragment = new RequestFragment();
		    	FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
		    	ft.add(R.id.home_tab_container, homeFragment, "request");
		    	ft.commit();
	    	}
	    }
//	    addTab(R.string.home_tab_profile, R.id.home_tab_container, "profile", ProfileFragment.class);
//	    addTab(R.string.home_tab_debug, R.id.home_tab_container, "debug", DebugFragment.class);

	    if (savedInstanceState!=null && actionBar.getNavigationMode()==ActionBar.NAVIGATION_MODE_TABS) {
	    	int pos = savedInstanceState.getInt("tabSelected");
	    	actionBar.selectTab(actionBar.getTabAt(pos));
	    }
	    
	    switch (GCMMessageReceiver.Action.valueOf(getIntent())) {
	    case GCM_RESPONSE_RECEIVED:
			forwardNotification();
			break;
		default:
			reload(false);
	    }
		
		final SharedPreferences prefs = getSharedPreferences(SolidalApp.class.getCanonicalName(), MODE_PRIVATE);
		if (!prefs.contains(Constants.PREF_NOTIFY)) {
			prefs.edit().putString(Constants.PREF_NOTIFY, "2").commit();
			new SherlockDialogFragment() {
				public Dialog onCreateDialog(Bundle savedInstanceState) {
					AlertDialog.Builder builder = new AlertDialog.Builder(HomeActivity.this)
						.setTitle(R.string.home_popup_title)
						.setMessage(R.string.home_popup_message)
						.setCancelable(false)
						.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								prefs.edit().putString(Constants.PREF_NOTIFY, "2").commit();
							}
						})
						.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								prefs.edit().putString(Constants.PREF_NOTIFY, "NONE").commit();
							}
						});
					return builder.create();
				}
			}.show(getSupportFragmentManager(), "disclaimer");
		}

	}
	
	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		if (savedInstanceState!=null && savedInstanceState.containsKey("request"))
			request = EndpointsUtils.fromBundle(savedInstanceState.getBundle("request"), Request.class);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getSupportMenuInflater();
		inflater.inflate(R.menu.home, menu);
		return true;
	}
	
	@Override
	protected void updateMenu() {
		super.updateMenu();
		try {
			Request req = (Request) app.getData(DataKey.REQUEST);
			boolean enabled = req!=null && req.getId()!=null && (req.getAccepted()==null || !req.getAccepted());
			MenuItem item = menu.findItem(R.id.action_cancel);
			item.setEnabled(enabled);
			item.getIcon().setAlpha(enabled ? 255 : 64);
		} catch(Exception e) {
			Log.w (SolidalApp.TAG, "Menu cancel update error: "+e);
		}
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Request req;
		switch (item.getItemId()) {
		case R.id.action_simulate:
			SharedPreferences prefs = getSharedPreferences(SolidalApp.class.getName(), MODE_PRIVATE);
			int n = prefs.getInt("simulation", 0) + 1;
			prefs.edit().putInt("simulation", n).commit();
			Location loc = app.getStatus().getLocation();
			Device device = (Device) app.getData(DataKey.DEVICE);
			req = new Request();
			req.setCredits(1 + (int) (Math.random()*10));
			req.setDetails("Simulated position n."+n);
			req.setDuration(60);
			req.setLatitude(loc.getLatitude() + 0.004d * Math.random() * Math.signum(Math.random()-0.5d));
			req.setLongitude(loc.getLongitude() + 0.004d * Math.random() * Math.signum(Math.random()-0.5d));
			req.setManualLocation(true);
			req.setMessage("Simulation n."+n);
			req.setDeviceId(device.getId());
			req.setTimestamp(System.currentTimeMillis());
			send(req);
			return true;
		case R.id.action_reload:
			reload(true);
			return true;
		case R.id.action_profile:
			startActivity(new Intent(this, RequestProfileActivity.class));
			return true;
		case R.id.action_cancel:
//			request = null;
//			app.setData(DataKey.REQUEST, null);
			req = (Request) app.getData(DataKey.REQUEST);
			Action.start(this, EndpointsRemoveRequest.class, req);
			getSupportLoaderManager().getLoader(getLoaderId()).reset();
			return true;
		case R.id.action_requests:
			startActivity(new Intent(this, ResponseActivity.class));
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (getSupportActionBar().getNavigationMode()==ActionBar.NAVIGATION_MODE_TABS)
			outState.putInt("tabSelected", getSupportActionBar().getSelectedTab().getPosition());
		if (request!=null)
			outState.putBundle("request", EndpointsUtils.toBundle(request));
	}
	
	@Override
	protected void onNewIntent(Intent intent) {
		
		super.onNewIntent(intent);
		
		if (Action.check(EndpointsInsertRequest.class, intent)
				|| Action.check(EndpointsRemoveRequest.class, intent)) {
			
			//TODO: include in refireActivity
			addOnResumeAction(new Runnable() {
				@Override
				public void run() {
					app.fireDataChanged(new DataEvent(HomeActivity.this, DataKey.REQUEST, true));
				}
			});
			
		} else {
			
			switch(GCMMessageReceiver.Action.valueOf(intent)) {
			case GCM_RESPONSE_RECEIVED:
				if (app.getData(DataKey.CHAT_REQUEST)!=null)
					((List<?>) app.getData(DataKey.CHAT_REQUEST)).clear();
				app.alert(getString(R.string.map_marker_accepted, intent.getStringExtra("message")));
				reload(true);
				break;
				
			default:
			}
			
		}
		
	}
	
	@Override
	public void onDataChanged(DataEvent event) {
		
		super.onDataChanged(event);
		
		switch (event.getKey()) {
		case FILE_RESPONSE:
			Response res = (Response) app.getData(DataKey.FILE_RESPONSE);
			if (res!=null && res.getCompleted()) {
				SharedPreferences prefs = getSharedPreferences(
						SolidalApp.class.getCanonicalName(), MODE_PRIVATE);
				prefs.edit().putBoolean(Constants.RESET_REQUEST, true).commit();
				app.setData(DataKey.FILE_RESPONSE, null);
				app.setData(DataKey.FILE_RESPONSE_PROFILE, null);
				app.setData(DataKey.ADDRESS_LOCATION_MANUAL, null);
				app.setData(DataKey.ADDRESS_TEXT_MANUAL, null);
				app.setData(DataKey.ADDRESS_LOCATION, app.getStatus().getLocation());
				if (app.getData(DataKey.CHAT_REQUEST)!=null)
					((List<?>) app.getData(DataKey.CHAT_REQUEST)).clear();
				app.setData(DataKey.REQUEST, null);
			}
			break;
			
		case REQUEST:
			Request req = (Request) app.getData(DataKey.REQUEST);
			updateMenu();
			if (req!=null && req.getId()!=null) {
				request = null;
				scheduleCheckExpiry();
			} else {
				descheduleCheckExpiry();
			}
			break;
			
		default:
			break;
		}
	}

	/**
	 * Check a request and send it the to server endpoint
	 * 
	 * @param request
	 * 		the client request object
	 */
	@Override
	public void send(Request request) {
		
		this.request = null;
		
		hideKeyboard();
		
		// Check location
		Location location = (Location) app.getData(DataKey.ADDRESS_LOCATION);
		if(location==null) {
			if (!checkLocationServices())
				Toast.makeText(this, R.string.check_location, Toast.LENGTH_SHORT).show();
			return;
		}
		request.setLatitude(location.getLatitude());
		request.setLongitude(location.getLongitude());
		request.setManualLocation(app.getData(DataKey.ADDRESS_LOCATION_MANUAL)!=null);
		
		// Check network
		if (app.getStatus().getNetworkStatus()!=NetworkUtils.Status.CONNECTED) {
			Toast.makeText(this, R.string.check_network, Toast.LENGTH_SHORT).show();
			return;
		}
				
		// Check registration
		Device device = (Device) app.getData(DataKey.DEVICE);
		if (device==null || app.getStatus().getGcmId()==null) {
			startActivity(new Intent(this, RequestProfileActivity.class));
			Toast.makeText(this, R.string.check_profile, Toast.LENGTH_SHORT).show();
			return;
		}
		request.setDeviceId(device.getId());
		
		// Check profile
		Profile profile = (Profile) app.getData(DataKey.PROFILE);
		if (profile==null) {
			startActivity(new Intent(this, RequestProfileActivity.class));
			Toast.makeText(this, R.string.check_profile, Toast.LENGTH_SHORT).show();
			return;
		}
		
		// Check username & phone
//		String phone = device.getTelephoneNumber();
//		if (phone==null || "".equals(phone))
//			phone = profile.getDefaultPhone();
		request.setSender(profile.getUsername());
		request.setSenderId(profile.getProfileId());
		
		// Check message
		if ("".equals(request.getMessage())) {
			Toast.makeText(this, R.string.check_message, Toast.LENGTH_SHORT).show();
			return;
		}
		
		// Check credits
		if (0 == request.getCredits()) {
			Toast.makeText(this, R.string.request_check_credits, Toast.LENGTH_SHORT).show();
			return;
		}
		
		// Check address
		if ("".equals(request.getDetails())) {
			Toast.makeText(this, R.string.request_check_address, Toast.LENGTH_SHORT).show();
			return;
		}
		
		// Show map if not visible
		if (getSupportActionBar().getNavigationMode()==ActionBar.NAVIGATION_MODE_TABS) {
			Tab t = getSupportActionBar().getTabAt(1);
			if("map".equals(t.getTag()))
				selectTab(1);
		}

		// Show confirm dialog
		this.request = request;
		app.fireDataChanged(new DataEvent(this, DataKey.REQUEST, true));
		new AlertDialog.Builder(this)
			.setMessage(R.string.request_alert_message)
			.setTitle(request.getDetails())
			.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
				@Override
	            public void onClick(DialogInterface dialog, int id) {
	            	send();
	            }
	        }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int id) {
	            	Toast.makeText(HomeActivity.this, 
        			R.string.request_check_address, 
        			Toast.LENGTH_SHORT).show();
				}
			}).create().show();
	}
	
	/**
	 * Send the request using new coordinates
	 * 
	 * @param pos
	 * 		the new coordinates
	 */
	@Override
	public void send(LatLng pos) {
		request.setLatitude(pos.latitude);
		request.setLongitude(pos.longitude);
		String address = (String) app.getData(DataKey.ADDRESS_TEXT);
		EditText detailsEdit = (EditText) findViewById(R.id.request_details_edit);
		if (detailsEdit!=null)
			address = detailsEdit.getText().toString();
		request.setDetails(address);
		send();
	}

	/**
	 * Send the current checked request
	 */
	private void send() {
		
	    try {
	    	
	    	// clear with a new temp request the request previously sent
	    	Request temp = new Request();
	    	temp.setLatitude(request.getLatitude());
	    	temp.setLongitude(request.getLongitude());
	    	temp.setDetails(request.getDetails());
	    	temp.setMessage(request.getMessage());
	    	temp.setCredits(request.getCredits());
	    	temp.setDuration(request.getDuration());
	    	temp.setExpired(false);
	    	temp.setAccepted(false);
	    	app.setData(DataKey.REQUEST, temp);
	    		    	
	    	Action.start(this, EndpointsInsertRequest.class, request);

	    	forceLoader();
	    		    	
	    } catch(Exception e) {
	    	
	    	app.setData(DataKey.REQUEST, null);
	    	Log.e(SolidalApp.TAG, "Error: "+e, e);
		    Toast.makeText(HomeActivity.this, "Error: "+e, Toast.LENGTH_SHORT).show();
	    	reload(true);
		    
	    }
	    
	}
	
	@Override
	public void openFile() {
		Intent intent = new Intent(this, RequestFileActivity.class);
		startActivity(intent);
	}
	
	@Override
	public Fragment selectTab(int position) {
	    ActionBar actionBar = getSupportActionBar();
	    Tab t = actionBar.getTabAt(position);
	    actionBar.selectTab(t);
	    return getSupportFragmentManager().findFragmentByTag((String) t.getTag());
	}
	
	@Override
	public Request getRequest() {
		return request;
	}
	
	@Override
	protected int getLoaderId() {
		return Constants.LOADER_REQUEST;
	}
	
	@Override
	public Loader<Request> onCreateLoader(int id, Bundle data) {
		return new EndpointsLoader<Request>(this, Request.class)
			.setFilters(data)
			.setMethod("getLast");
	}
	
	@Override
	public void onLoadFinished(final Loader<Request> loader, final Request result) {
		
		// if sending or still loading don't try to load
		Request temp = (Request) app.getData(DataKey.REQUEST);
		boolean sending = temp!=null && temp.getId()==null;
		if (sending) {
			setLoading(false);
			return;
		}
		
		// make sure it is executed when activity is resumed
		addOnResumeAction(new Runnable() {
			
			public void run() {
				
				try {
					
//					Log.i(SolidalApp.TAG, "Request loaded: " + (result!=null ? result.getMessage()+","+result.getCompleted()+","+result.getExpired()+","+result.getCanceled() : "null"));
					if (result!=null && !result.getCompleted() && !result.getExpired() && !result.getCanceled()) {
						
						descheduleCheckExpiry();
						
						final ActionBar actionBar = getSupportActionBar();
						
						if (actionBar.getSelectedNavigationIndex()==0 && actionBar.getNavigationMode()==ActionBar.NAVIGATION_MODE_TABS) {
							Handler h = new Handler(loader.getContext().getMainLooper());
							h.post(new Runnable() {
								@Override
								public void run() {
									actionBar.setSelectedNavigationItem(1);
								}
							});
						}
						
						app.setData(DataKey.ADDRESS_LOCATION_MANUAL, true);
						app.setData(DataKey.ADDRESS_LOCATION, app.getStatus()
								.newLocation(result.getLatitude(), result.getLongitude()));
	//					app.setData(DataKey.ADDRESS_TEXT_MANUAL, true);
						app.setData(DataKey.REQUEST, result);
					} else {
						app.setData(DataKey.REQUEST, null);
					}
					
				} finally {				
					setLoading(false);
				}
				
			}
		});
		
		
	}

	@Override
	public void onLoaderReset(Loader<Request> loader) {
		Log.i(SolidalApp.TAG, "Loader Reset: "+getClass().getSimpleName());
//		loader.reset();
	}
	
}
